home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-04-04 | 88.3 KB | 2,857 lines |
- Newsgroups: comp.sources.unix
- From: slf@cs.mu.OZ.AU (Stewart Forster)
- Subject: v26i097: TCX v1.1 - Transparently Compressed Executables for UNIX, Part01/01
- Sender: unix-sources-moderator@vix.com
- Approved: paul@vix.com
-
- Submitted-By: slf@cs.mu.OZ.AU (Stewart Forster)
- Posting-Number: Volume 26, Issue 97
- Archive-Name: tcx-1.1/part01
-
- [ This version (1.1) of TCX is also available anonymous via FTP at
- turiel.cs.mu.OZ.AU:pub/tcx1.1.tar.Z
- or 192.43.207.19:pub/tcx1.1.tar.Z
- --vix ]
-
- This release fixes many small bugs which prevented recompression of execs
- in certain circumstances. It also adds a verified port to IBM's AIX, and
- an initial port to Linux which is not verified to be working (but probably
- does with fingers crossed). Further support for the handling of symlinks
- to shell scripts was also tested and added.
-
- For those who don't know, TCX allows you to compress Unix executables
- using a compression algorithm of your choice (however GNU's gzip is highly
- recommended). Once compressed, the executable may be run as normal. The
- system provides transparent uncompression, (then execution), and finally
- recompression of the executable. Recompression takes place after an installer
- defined interval of disuse, so one may balance the disk and cpu resources of
- the machine according to local needs, hence allowing for a smooth control of
- compressed disk space. Features include emergency procedures in case of disk
- shortages when uncompressing, and a fairly robust scheme whereby files will not
- be lost if the system crashes during operations. It also works for NFS mounted
- executables.
-
- Currently supported OS types are Ultrix, SunOS, Irix, AIX and Linux.
- Other OS support will come as nice people provide me with patches. TCX is
- currently in use at the University of Melbourne, so it has continuing support.
-
- slf@cs.mu.OZ.AU (Stewart Forster)
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 1)."
- # Contents: COPYING MANIFEST Makefile README VERSION config.h tcx.1
- # tcx.c untcx.1 untcx.c
- # Wrapped by vixie@gw.home.vix.com on Mon Apr 5 03:06:07 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'COPYING' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'COPYING'\"
- else
- echo shar: Extracting \"'COPYING'\" \(17982 characters\)
- sed "s/^X//" >'COPYING' <<'END_OF_FILE'
- X GNU GENERAL PUBLIC LICENSE
- X Version 2, June 1991
- X
- X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- X 675 Mass Ave, Cambridge, MA 02139, USA
- X Everyone is permitted to copy and distribute verbatim copies
- X of this license document, but changing it is not allowed.
- X
- X Preamble
- X
- X The licenses for most software are designed to take away your
- freedom to share and change it. By contrast, the GNU General Public
- License is intended to guarantee your freedom to share and change free
- software--to make sure the software is free for all its users. This
- General Public License applies to most of the Free Software
- XFoundation's software and to any other program whose authors commit to
- using it. (Some other Free Software Foundation software is covered by
- the GNU Library General Public License instead.) You can apply it to
- your programs, too.
- X
- X When we speak of free software, we are referring to freedom, not
- price. Our General Public Licenses are designed to make sure that you
- have the freedom to distribute copies of free software (and charge for
- this service if you wish), that you receive source code or can get it
- if you want it, that you can change the software or use pieces of it
- in new free programs; and that you know you can do these things.
- X
- X To protect your rights, we need to make restrictions that forbid
- anyone to deny you these rights or to ask you to surrender the rights.
- These restrictions translate to certain responsibilities for you if you
- distribute copies of the software, or if you modify it.
- X
- X For example, if you distribute copies of such a program, whether
- gratis or for a fee, you must give the recipients all the rights that
- you have. You must make sure that they, too, receive or can get the
- source code. And you must show them these terms so they know their
- rights.
- X
- X We protect your rights with two steps: (1) copyright the software, and
- X(2) offer you this license which gives you legal permission to copy,
- distribute and/or modify the software.
- X
- X Also, for each author's protection and ours, we want to make certain
- that everyone understands that there is no warranty for this free
- software. If the software is modified by someone else and passed on, we
- want its recipients to know that what they have is not the original, so
- that any problems introduced by others will not reflect on the original
- authors' reputations.
- X
- X Finally, any free program is threatened constantly by software
- patents. We wish to avoid the danger that redistributors of a free
- program will individually obtain patent licenses, in effect making the
- program proprietary. To prevent this, we have made it clear that any
- patent must be licensed for everyone's free use or not licensed at all.
- X
- X The precise terms and conditions for copying, distribution and
- modification follow.
- X
- X GNU GENERAL PUBLIC LICENSE
- X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- X
- X 0. This License applies to any program or other work which contains
- a notice placed by the copyright holder saying it may be distributed
- under the terms of this General Public License. The "Program", below,
- refers to any such program or work, and a "work based on the Program"
- means either the Program or any derivative work under copyright law:
- that is to say, a work containing the Program or a portion of it,
- either verbatim or with modifications and/or translated into another
- language. (Hereinafter, translation is included without limitation in
- the term "modification".) Each licensee is addressed as "you".
- X
- Activities other than copying, distribution and modification are not
- covered by this License; they are outside its scope. The act of
- running the Program is not restricted, and the output from the Program
- is covered only if its contents constitute a work based on the
- Program (independent of having been made by running the Program).
- Whether that is true depends on what the Program does.
- X
- X 1. You may copy and distribute verbatim copies of the Program's
- source code as you receive it, in any medium, provided that you
- conspicuously and appropriately publish on each copy an appropriate
- copyright notice and disclaimer of warranty; keep intact all the
- notices that refer to this License and to the absence of any warranty;
- and give any other recipients of the Program a copy of this License
- along with the Program.
- X
- You may charge a fee for the physical act of transferring a copy, and
- you may at your option offer warranty protection in exchange for a fee.
- X
- X 2. You may modify your copy or copies of the Program or any portion
- of it, thus forming a work based on the Program, and copy and
- distribute such modifications or work under the terms of Section 1
- above, provided that you also meet all of these conditions:
- X
- X a) You must cause the modified files to carry prominent notices
- X stating that you changed the files and the date of any change.
- X
- X b) You must cause any work that you distribute or publish, that in
- X whole or in part contains or is derived from the Program or any
- X part thereof, to be licensed as a whole at no charge to all third
- X parties under the terms of this License.
- X
- X c) If the modified program normally reads commands interactively
- X when run, you must cause it, when started running for such
- X interactive use in the most ordinary way, to print or display an
- X announcement including an appropriate copyright notice and a
- X notice that there is no warranty (or else, saying that you provide
- X a warranty) and that users may redistribute the program under
- X these conditions, and telling the user how to view a copy of this
- X License. (Exception: if the Program itself is interactive but
- X does not normally print such an announcement, your work based on
- X the Program is not required to print an announcement.)
- X
- These requirements apply to the modified work as a whole. If
- identifiable sections of that work are not derived from the Program,
- and can be reasonably considered independent and separate works in
- themselves, then this License, and its terms, do not apply to those
- sections when you distribute them as separate works. But when you
- distribute the same sections as part of a whole which is a work based
- on the Program, the distribution of the whole must be on the terms of
- this License, whose permissions for other licensees extend to the
- entire whole, and thus to each and every part regardless of who wrote it.
- X
- Thus, it is not the intent of this section to claim rights or contest
- your rights to work written entirely by you; rather, the intent is to
- exercise the right to control the distribution of derivative or
- collective works based on the Program.
- X
- In addition, mere aggregation of another work not based on the Program
- with the Program (or with a work based on the Program) on a volume of
- a storage or distribution medium does not bring the other work under
- the scope of this License.
- X
- X 3. You may copy and distribute the Program (or a work based on it,
- under Section 2) in object code or executable form under the terms of
- Sections 1 and 2 above provided that you also do one of the following:
- X
- X a) Accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of Sections
- X 1 and 2 above on a medium customarily used for software interchange; or,
- X
- X b) Accompany it with a written offer, valid for at least three
- X years, to give any third party, for a charge no more than your
- X cost of physically performing source distribution, a complete
- X machine-readable copy of the corresponding source code, to be
- X distributed under the terms of Sections 1 and 2 above on a medium
- X customarily used for software interchange; or,
- X
- X c) Accompany it with the information you received as to the offer
- X to distribute corresponding source code. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form with such
- X an offer, in accord with Subsection b above.)
- X
- The source code for a work means the preferred form of the work for
- making modifications to it. For an executable work, complete source
- code means all the source code for all modules it contains, plus any
- associated interface definition files, plus the scripts used to
- control compilation and installation of the executable. However, as a
- special exception, the source code distributed need not include
- anything that is normally distributed (in either source or binary
- form) with the major components (compiler, kernel, and so on) of the
- operating system on which the executable runs, unless that component
- itself accompanies the executable.
- X
- If distribution of executable or object code is made by offering
- access to copy from a designated place, then offering equivalent
- access to copy the source code from the same place counts as
- distribution of the source code, even though third parties are not
- compelled to copy the source along with the object code.
- X
- X 4. You may not copy, modify, sublicense, or distribute the Program
- except as expressly provided under this License. Any attempt
- otherwise to copy, modify, sublicense or distribute the Program is
- void, and will automatically terminate your rights under this License.
- However, parties who have received copies, or rights, from you under
- this License will not have their licenses terminated so long as such
- parties remain in full compliance.
- X
- X 5. You are not required to accept this License, since you have not
- signed it. However, nothing else grants you permission to modify or
- distribute the Program or its derivative works. These actions are
- prohibited by law if you do not accept this License. Therefore, by
- modifying or distributing the Program (or any work based on the
- Program), you indicate your acceptance of this License to do so, and
- all its terms and conditions for copying, distributing or modifying
- the Program or works based on it.
- X
- X 6. Each time you redistribute the Program (or any work based on the
- Program), the recipient automatically receives a license from the
- original licensor to copy, distribute or modify the Program subject to
- these terms and conditions. You may not impose any further
- restrictions on the recipients' exercise of the rights granted herein.
- You are not responsible for enforcing compliance by third parties to
- this License.
- X
- X 7. If, as a consequence of a court judgment or allegation of patent
- infringement or for any other reason (not limited to patent issues),
- conditions are imposed on you (whether by court order, agreement or
- otherwise) that contradict the conditions of this License, they do not
- excuse you from the conditions of this License. If you cannot
- distribute so as to satisfy simultaneously your obligations under this
- License and any other pertinent obligations, then as a consequence you
- may not distribute the Program at all. For example, if a patent
- license would not permit royalty-free redistribution of the Program by
- all those who receive copies directly or indirectly through you, then
- the only way you could satisfy both it and this License would be to
- refrain entirely from distribution of the Program.
- X
- If any portion of this section is held invalid or unenforceable under
- any particular circumstance, the balance of the section is intended to
- apply and the section as a whole is intended to apply in other
- circumstances.
- X
- It is not the purpose of this section to induce you to infringe any
- patents or other property right claims or to contest validity of any
- such claims; this section has the sole purpose of protecting the
- integrity of the free software distribution system, which is
- implemented by public license practices. Many people have made
- generous contributions to the wide range of software distributed
- through that system in reliance on consistent application of that
- system; it is up to the author/donor to decide if he or she is willing
- to distribute software through any other system and a licensee cannot
- impose that choice.
- X
- This section is intended to make thoroughly clear what is believed to
- be a consequence of the rest of this License.
- X
- X 8. If the distribution and/or use of the Program is restricted in
- certain countries either by patents or by copyrighted interfaces, the
- original copyright holder who places the Program under this License
- may add an explicit geographical distribution limitation excluding
- those countries, so that distribution is permitted only in or among
- countries not thus excluded. In such case, this License incorporates
- the limitation as if written in the body of this License.
- X
- X 9. The Free Software Foundation may publish revised and/or new versions
- of the General Public License from time to time. Such new versions will
- be similar in spirit to the present version, but may differ in detail to
- address new problems or concerns.
- X
- XEach version is given a distinguishing version number. If the Program
- specifies a version number of this License which applies to it and "any
- later version", you have the option of following the terms and conditions
- either of that version or of any later version published by the Free
- Software Foundation. If the Program does not specify a version number of
- this License, you may choose any version ever published by the Free Software
- XFoundation.
- X
- X 10. If you wish to incorporate parts of the Program into other free
- programs whose distribution conditions are different, write to the author
- to ask for permission. For software which is copyrighted by the Free
- Software Foundation, write to the Free Software Foundation; we sometimes
- make exceptions for this. Our decision will be guided by the two goals
- of preserving the free status of all derivatives of our free software and
- of promoting the sharing and reuse of software generally.
- X
- X NO WARRANTY
- X
- X 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- REPAIR OR CORRECTION.
- X
- X 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGES.
- X
- X END OF TERMS AND CONDITIONS
- X
- X Appendix: How to Apply These Terms to Your New Programs
- X
- X If you develop a new program, and you want it to be of the greatest
- possible use to the public, the best way to achieve this is to make it
- free software which everyone can redistribute and change under these terms.
- X
- X To do so, attach the following notices to the program. It is safest
- to attach them to the start of each source file to most effectively
- convey the exclusion of warranty; and each file should have at least
- the "copyright" line and a pointer to where the full notice is found.
- X
- X <one line to give the program's name and a brief idea of what it does.>
- X Copyright (C) 19yy <name of author>
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 2 of the License, or
- X (at your option) any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- Also add information on how to contact you by electronic and paper mail.
- X
- If the program is interactive, make it output a short notice like this
- when it starts in an interactive mode:
- X
- X Gnomovision version 69, Copyright (C) 19yy name of author
- X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- X This is free software, and you are welcome to redistribute it
- X under certain conditions; type `show c' for details.
- X
- The hypothetical commands `show w' and `show c' should show the appropriate
- parts of the General Public License. Of course, the commands you use may
- be called something other than `show w' and `show c'; they could even be
- mouse-clicks or menu items--whatever suits your program.
- X
- You should also get your employer (if you work as a programmer) or your
- school, if any, to sign a "copyright disclaimer" for the program, if
- necessary. Here is a sample; alter the names:
- X
- X Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- X `Gnomovision' (which makes passes at compilers) written by James Hacker.
- X
- X <signature of Ty Coon>, 1 April 1989
- X Ty Coon, President of Vice
- X
- This General Public License does not permit incorporating your program into
- proprietary programs. If your program is a subroutine library, you may
- consider it more useful to permit linking proprietary applications with the
- library. If this is what you want to do, use the GNU Library General
- Public License instead of this License.
- END_OF_FILE
- if test 17982 -ne `wc -c <'COPYING'`; then
- echo shar: \"'COPYING'\" unpacked with wrong size!
- fi
- # end of 'COPYING'
- fi
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(424 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- X File Name Archive # Description
- X-----------------------------------------------------------
- X COPYING 1
- X MANIFEST 1 This shipping list
- X Makefile 1
- X README 1
- X VERSION 1
- X config.h 1
- X tcx.1 1
- X tcx.c 1
- X untcx.1 1
- X untcx.c 1
- END_OF_FILE
- if test 424 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(642 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X#
- X# Makefile for tcx
- X#
- X# Author : Stewart Forster, University Of Melbourne, 25/31993
- X#
- X
- X# C compiler of your choice. Should be ansi'ish
- CC = cc # IRIX, ULTRIX, AIX
- X#CC = gcc # SUNOS
- X
- X
- X# Cflags of choice.
- CFLAGS = -s -O # Most OS's
- X#CFLAGS = -s -O6 -fomit-frame-pointer -Wall # Linux
- X
- X
- X# Any libraries
- LIBS = -lmalloc -lc_s # IRIX
- X#LIBS = # SUNOS, ULTRIX, AIX
- X
- X
- all: tcx untcx
- X
- tcx: tcx.c config.h
- X $(CC) $(CFLAGS) -o tcx tcx.c $(LIBS)
- X
- untcx: untcx.c config.h
- X $(CC) $(CFLAGS) -o untcx untcx.c $(LIBS)
- X
- shar:
- X shar -c -l 45 -o tcx README VERSION COPYING Makefile tcx.1 untcx.1 tcx.c config.h untcx.c
- X
- clean:
- X /bin/rm -f *.o tcx untcx
- END_OF_FILE
- if test 642 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(5296 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X TCX - Transparently Compressed Executables (For Unix)
- X
- X by
- X
- X Stewart Forster, University Of Melbourne, 1993
- X
- TCX is a system designed for the transparent decompression, execution
- and recompression of executables under Unix. It allows configuration
- options such as the type of compression system used (compress(1),
- gzip(1), your own local system etc), timeouts between recompressions,
- and emergency directories in case a decompression fails from shortage
- of disk space. The system is designed with a reasonable amount of
- robustness in mind, such as in the event of system crashes, or races
- on trying to uncompress, compress or execute something.
- X
- X Currently TCX is only proven to run on Irix 4.*, Ultrix 4.2
- or higher, and SunOs 4.1.1 or higher. It may run on other releases
- of these OS's but has not been tested. It should also be relatively
- easy to port to other OS's as much of the code is fairly straight
- forward.
- X
- X The system is used here at the Department of Computer Science
- University Of Melbourne, and in other departments on campus. This is
- the first official release of TCX to the world, so please feel free
- to comment or help in bug fixes and machine reports by sending email
- to slf@cs.mu.OZ.AU
- X
- X---------------------------------------------------------------------
- X
- X INSTALLATION
- X
- TCX is a small package with just the following files. If you don't
- have these three file, get a complete distribution.
- X
- X config.h
- X tcx.c
- X untcx.c
- X
- XFirst read the "FURTHER INFO" section below before configuring TCX
- for your system, since it may influence some of your decisions.
- X
- To configure TCX, edit the config.h file. There are enough directions
- therein to help you configure for your system. TCX relies on the
- compression system you use to barf when the filesystem gets full
- and return a fail exit code. If the compression system you use
- doesn't do this, you run the risk of losing files. The GNU gzip
- package is known to do the correct safety checks and exit accordingly.
- X
- Once done editing the config file, edit the Makefile to set the C
- compiler and libraries for your system, and compile.
- Don't worry if your optimizer complains of no exit points in the
- procedures called "check_tcxd_mode", "untcx_and_exec_local", and
- X"untcx_and_exec_nfs" when compiling untcx.c, these are normal.
- X
- The tcx, and untcx executables must be placed at the pathnames you
- specified for them in config.h, if they are not there, the system
- will NOT work. eg.
- X
- X cp tcx /usr/local/bin/tcx
- X cp untcx /usr/local/bin/untcx
- X
- Untcx must also be installed setuid, so issue the following command.
- X
- X chown root /usr/local/bin/untcx
- X chmod 4711 /usr/local/bin/untcx (or path you chose)
- X
- Do not install the "tcx" executable setuid to anyone.
- X
- and copy the manual pages to your regular man directory and read them.
- X
- X The installation is now complete.
- X
- X----------------------------------------------------------------------
- X
- X TESTING YOUR INSTALLATION
- X
- You can now try running "tcx" on an innocuous executable to transform
- it, and then try running it. Wait for the timeout interval you
- specified (after disuse, which means not even reading the file) and it
- should recompress. If it doesn't recompress after about twice the
- interval specified, check the following.
- X
- X1) Access times on the file. MAKE SURE it wasn't touched before suspecting
- X something is wrong.
- X2) That the daemon mode for untcx started correctly. The pid should be
- X stored in ENFSDIR/.lock. Assuming ENFSDIR is /tmp/exec as in the
- X distributed config file, issue
- X
- X ps `cat /tmp/exec/.lock` and check that the daemon started.
- X
- X If it didn't, there is a minor problem with permissions, or maybe
- X you specified a read-only file system for ENFSDIR.
- X3) Check if you installed tcx where PATHTCX in the config file said
- X where it was.
- X4) Check that the uncompressor is where PATHUNPACK in the the config
- X file says it is.
- X
- If all else comes to nought, look into the source code, or mail your
- system configuration and config file to slf@cs.mu.OZ.AU, and I'll
- try and see what can be done.
- X
- X----------------------------------------------------------------------
- X
- X FUTHER INFO / POTENTIAL BUGS
- X
- Users may experience a slight delay when a TCX executable is started up
- due the decompression phase. If this becomes a problem for large
- executables, you should probably discourage use of TCX on these huge
- binaries. The "gzip" system decompresses at around 500-700K/sec on the
- systems I tested it on, which are all around the 25 SPECmark rating.
- X
- Don't use TCX on NFS mounted shell scripts which rely on `dirname $0`
- because TCX cannot fool the shell into giving it a spoof $0, like it
- can with binaries. This may be the only case (other than setuid
- programs) where TCX will break something.
- X
- X----------------------------------------------------------------------
- X
- X THANKS
- X
- Special thanks go to Robert Elz, who provided invaluable input,
- suggestions and clarifications on the whole idea.
- X
- Thanks also to Jeff Shultz who provided some potential "sticky" cases
- which gave me some more work to do (plus made tcx more robust).
- X
- Many thanks go the the overwhelming input provided by many people
- around the world, all interested in seeing TCX working correctly on
- their system. Your input is what makes good software better.
- X
- X Stewart.
- X
- END_OF_FILE
- if test 5296 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'VERSION' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'VERSION'\"
- else
- echo shar: Extracting \"'VERSION'\" \(4546 characters\)
- sed "s/^X//" >'VERSION' <<'END_OF_FILE'
- Version 1.1 (5/4/1993) Stewart Forster
- X untcx.c v1.0.5
- X - Fixed statfs code which had the wrong call args for
- X SunOs and Ultrix (but didn't make any diff though).
- X Thanks to H.J.Lu for pointing that one out
- X - Completed AIX port
- X - Added LINUX patches, these may be somewhat confused as
- X the person who provided the patches did not understand
- X the way untcx invokes itself, so they were re-patched by
- X me without a machine to test them on.
- X Thanks to H.J.Lu for the patches.
- X - Fixed timeout code which was resetting inode mod times
- X which I was later using to see if file had changed.
- X This would only prevent execs from recompressing if they
- X had been running for longer than the LOCALTIMEOUT period.
- X - Fixed checks on symlinks over NFS.
- X - Fixed bug whereby if an exec was run, in between the
- X latent stage after recompression and before untcx noted
- X that the recompression had completed, it would not get
- X recompressed.
- X config.h v1.0.3
- X - Removed the need for utime() dependent includes.
- X - Added AIX #defs
- Version 1.0.4 (1/4/1993) Stewart Forster
- X untcx.c v1.0.4
- X - Added symlink code to handle cases where a symlink to
- X a shell script resulted in the shell script being called
- X with $0 was being set to the path of the script, and not
- X the symlink. Added stuff so untcx would create symlinks
- X in ENFSDIR as well, and manage them (including floating
- X links) properly. (I hope!) Resulting fix results in
- X `basename $0` equalling the basename of the symlink,
- X although `dirname $0` will be different (unavoidable).
- X This problem should affect almost nobody, unless a shell
- X script gets picky about `dirname $0`, in which case you
- X should not tcx such scripts. :-(
- X - Changed the execl for the "unpacker" to pass along the
- X pathname of the uncompressor through argv[0], rather than
- X "unpacker", which was what was confusing the Unix compress
- X system (silly me!)
- X Thanks to Lionel Mallet for pointing this out.
- X tcx.c v1.0.4
- X - Changed the execl for the "packer" to pass along the
- X pathname of the compressor through argv[0], rather than
- X "packer", which was what was confusing the Unix compress
- X system (silly me!)
- X Thanks to Lionel Mallet for pointing this out.
- Version 1.0.3 (30/3/1993) Stewart Forster
- X untcx.c v1.0.3
- X - Fixed a race condition bug whereby under SUNOS, if
- X untcx encountered a local executable, that had just been
- X unpacked while it was setting up, it would get stuck in
- X an infinite loop. This race is pretty slim, but may have
- X happened on large multi-user systems.
- X - Fixed symlink resolving bug. Didn't check for length
- X returned from readlink, and was strcat-ing strings that
- X were not always null-terminated!
- X - Added #ifdef to allow tcx to ALWAYS unpack to /tmp.
- X Suggestion by Mike Lawley.
- X - Added code to unpack to ENFSDIR if file being unpacked
- X has a link count greater than 1, so that hard links may
- X be preserved.
- X tcx.c v1.0.3
- X - Added symbolic link resolving code from untcx.c, to
- X allow tcx to operate on symlinks. Added symlink bug fix.
- X Suggestion by Richard van de Stadt.
- X - Added code to check for hard link count, and abort with
- X a warning if count is greater than 1. This prevents the
- X destruction of hard links when packing.
- X config.h v1.0.2
- X - Added UNPACK_IN_PLACE option definition.
- X
- Version 1.0.2 (27/3/1993) Stewart Forster
- X untcx.c v1.0.2
- X - Added open file table reference count to internal hash
- X tables for SUNOS. This means that inodes won't have to
- X time out before recompressing the file they point to.
- X Thanks to Mike Lawley for pointing out problem
- X - Fixed tragic bug in pathname resolution that would have
- X caused a lot of problems when a program needs to access
- X files in the directory in which it was invoked, and not
- X where it lived! Also the cause of incorrect pathname
- X generation on NFS mounted executables placed in ENFSDIR.
- X Thanks to many who directly and indirectly reported this.
- X
- Version 1.0.1 (26/3/1993) Stewart Forster
- X tcx.c v1.0.2
- X - Worked around Ultrix file lock problem on NFS mounted
- X files. Ultrix 4.2 can't lock NFS files.
- X v1.0.1
- X - Rewrote scratch file creation code to fix Ultrix
- X ftruncate bug reported by John Adcock and Joel Fine.
- X Removed the need for ftruncate().
- X untcx.c v1.0.1
- X - Fixed trailing slash on mkdir argument which Ultrix
- X barfs on. Reported by John Adcock.
- X config.h v1.0.1
- X - Added comments about not using tmpfs on SUNOS for ENFSDIR
- X
- Version 1.0 (25/3/1993) (Original Release) Stewart Forster
- X tcx.c v1.0
- X untcx.c v1.0
- X config.h v1.0
- END_OF_FILE
- if test 4546 -ne `wc -c <'VERSION'`; then
- echo shar: \"'VERSION'\" unpacked with wrong size!
- fi
- # end of 'VERSION'
- fi
- if test -f 'config.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'config.h'\"
- else
- echo shar: Extracting \"'config.h'\" \(8049 characters\)
- sed "s/^X//" >'config.h' <<'END_OF_FILE'
- X/* config.h, Version 1.0.3, 5/4/1993 by Stewart Forster */
- X
- X/************************************************************************/
- X/* Copyright (C) 1993 Stewart Forster */
- X/* This program is free software; you can redistribute it and/or modify*/
- X/* it under the terms of the GNU General Public License as published by*/
- X/* the Free Software Foundation; either version 2, or (at your option) */
- X/* any later version. */
- X/* */
- X/* This program is distributed in the hope that it will be useful, */
- X/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
- X/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
- X/* GNU General Public License for more details. */
- X/* */
- X/* You should have received a copy of the GNU General Public License */
- X/* along with this program; if not, write to the Free Software */
- X/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- X/************************************************************************/
- X
- X
- X/************************************************************************/
- X/* OS TYPE DEFINITION */
- X/* Define one of the following where appropriate */
- X/************************************************************************/
- X
- X/* #define SUNOS /* */
- X#define IRIX /* */
- X/* #define AIX /* */
- X/* #define ULTRIX /* */
- X/* #define LINUX /* */
- X
- X/************************************************************************/
- X/* SUNOS requires the pstat command to be available. This is part of */
- X/* the SunOs distribution but fix this following path if it's wrong. */
- X/************************************************************************/
- X
- X#ifdef SUNOS
- X#define PSTATI "/usr/etc/pstat -i"
- X#endif
- X
- X/************************************************************************/
- X/* PATHUNTCX is the pathname where the untcx executable resides. Note */
- X/* that this is the interpreter/unpacker and hence must exist with this */
- X/* path, or else the whole system will fail! This path should also be on*/
- X/* a filesystem which the local system trusts setuid binaries from, */
- X/* since PATHUNTCX must run setuid to root. */
- X/************************************************************************/
- X
- X#define PATHUNTCX "/usr/local/bin/untcx"
- X
- X/************************************************************************/
- X/* PATHTCX is the pathname to the tcx executable. This should NOT be */
- X/* installed setuid root. */
- X/************************************************************************/
- X
- X#define PATHTCX "/usr/local/bin/tcx"
- X
- X/************************************************************************/
- X/* PATHPACKER is the pathname to the compression program you wish to use*/
- X/* with the system. PACKEROPTS is an optional definition of options you */
- X/* wish to pass to the packer program. NB. The compression program must */
- X/* be a `filter', that is, it is capable of reading from stdion and */
- X/* compressing to stdout. */
- X/************************************************************************/
- X
- X#define PATHPACKER "/usr/local/bin/gzip"
- X/*#define PACKEROPTS "-7" /* Optional */
- X
- X/************************************************************************/
- X/* PATHUNPACK and the optional UNPACKOPTS serve a similar purpose to */
- X/* PATHPACKER and PACKEROPTS above. */
- X/************************************************************************/
- X
- X#define PATHUNPACK "/usr/local/bin/gzip"
- X#define UNPACKOPTS "-d" /* Optional */
- X
- X/************************************************************************/
- X/* UNPACK_IN_PLACE instructs the uncrompressor to unpack an executable */
- X/* where it lives if it resides on the local machine. This is useful */
- X/* on machines with small /tmp's, plus it evenly distributes the disk */
- X/* workload. It is generally deemed useful to have it turned on. */
- X/* Comment this out if you have a large unpack area for ENFSDIR (below) */
- X/* or if you have very limited CPU resources, since unpacking in place */
- X/* means that untcx will have to recompress the file later, rather than */
- X/* just deleting the temporary one from ENFSDIR. */
- X/************************************************************************/
- X
- X#define UNPACK_IN_PLACE /* */
- X
- X/************************************************************************/
- X/* ENFSDIR is the pathname to the directory where emergency (out of disk*/
- X/* space locally) or NFS mounted executables get unpacked to. */
- X/* On SUNOS, if you are using the "tmpfs", you will have to set ENFSDIR */
- X/* to a "real disk". (A "real disk" may also be an NFS mounted partition*/
- X/* to which the machine has root access to). There seems to be some */
- X/* problem with fcntl locks on SUNOS tmpfs. */
- X/************************************************************************/
- X
- X#define ENFSDIR "/tmp/exec"
- X
- X/************************************************************************/
- X/* SCANRATE is the interval in seconds which the tcx daemon waits before*/
- X/* rescanning all files it is currently managing, for recompression in */
- X/* the case of local files, or deletion from ENFSDIR in the case of */
- X/* emergency or NFS mounted executables. Note that SCANRATE should */
- X/* probably not be larger than ENFSTIMEOUT or LOCALTIMEOUT defined */
- X/* below, otherwise you will undermine the purpose of those variables. */
- X/************************************************************************/
- X
- X#define SCANRATE 60 /* 60 seconds between scans */
- X
- X/************************************************************************/
- X/* ENFSTIMEOUT is the least number of seconds of disuse of an executable*/
- X/* residing in ENFSDIR the tcx daemon will wait for, before it attempts */
- X/* to delete the executable. This should be set quite low if there isn't*/
- X/* much disk space available in ENFSDIR. */
- X/* On SUNOS, this value only sets in after the inode is timed out of the*/
- X/* inode cache. This problem will be addressed in a future release. */
- X/************************************************************************/
- X
- X#define ENFSTIMEOUT 300 /* 5 minutes of inactivity */
- X
- X/************************************************************************/
- X/* LOCALTIMEOUT is the least number of seconds of disuse of an */
- X/* executable residing locally on the system that the tcx will wait */
- X/* before attempting to repack the executable. */
- X/* On SUNOS, this value only sets in after the inode is timed out of the*/
- X/* inode cache. This problem will be addressed in a future release. */
- X/************************************************************************/
- X
- X#define LOCALTIMEOUT 3600 /* 1 hour of inactivity */
- X
- X
- X/************************************************************************/
- X/************************************************************************/
- X/* You should not need to edit anything after this point */
- X/************************************************************************/
- X/************************************************************************/
- X
- X#define MAXHEADERSIZE 256
- X#define SIGTYPE int
- X
- X/* Define PUSLEEP (portable usleep definition) */
- X
- X#if defined(LINUX)
- X#define __USE_BSD_SIGNAL
- X#define SIGTYPE void
- X#endif
- X
- X#if defined(IRIX)
- X#define _BSD_SIGNALS
- X#define PUSLEEP(x) (sginap((long)((x)/10000)))
- X#endif
- X
- X#if defined(ULTRIX) || defined(SUNOS) || defined(AIX) || defined(LINUX)
- X#define PUSLEEP(x) (usleep(x)) /* usleep code in untcx.c for ULTRIX */
- X#endif
- X
- X#ifdef __STDC__
- X#include <stdlib.h>
- X#endif
- X#include <unistd.h>
- X#include <sys/time.h>
- X#include <sys/wait.h>
- X
- X#if defined(AIX)
- X#include <sys/id.h>
- X#endif
- X
- X#include <sys/types.h>
- X
- X#if defined(ULTRIX) || defined(LINUX)
- X#include <sys/param.h>
- X#include <sys/mount.h>
- X#endif
- X
- X#if defined(IRIX) || defined(AIX)
- X#include <sys/statfs.h>
- X#endif
- X
- X#if defined(SUNOS) || defined(LINUX)
- X#include <sys/vfs.h>
- X#endif
- X
- X#include <sys/stat.h>
- X#include <fcntl.h>
- X#include <string.h>
- X#include <errno.h>
- X#include <signal.h>
- X#include <stdio.h>
- X
- X#ifndef MAXPATHLEN
- X#define MAXPATHLEN 1024
- X#endif
- END_OF_FILE
- if test 8049 -ne `wc -c <'config.h'`; then
- echo shar: \"'config.h'\" unpacked with wrong size!
- fi
- # end of 'config.h'
- fi
- if test -f 'tcx.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tcx.1'\"
- else
- echo shar: Extracting \"'tcx.1'\" \(2208 characters\)
- sed "s/^X//" >'tcx.1' <<'END_OF_FILE'
- X.TH TCX 1 "19 March 1993"
- X.UC Melb
- X.SH NAME
- tcx \- Transparantly compress executables
- X.SH SYNOPSIS
- tcx filename
- X.SH DESCRIPTION
- X.B Tcx
- will replace an executable with a compressed version of it that is still
- capable of being executed. The amount of savings will depend on the
- compression algorithm configured for use by tcx.
- An executable compressed with tcx can be run as per normal with (hopefully) no
- side effects other than a minor delay in startup time.
- X.PP
- XExecutables local to the system (not NFS mounted) are uncompressed in place
- and recompressed again some time after it stops being used. The standard
- timeout is 1/2 an hour.
- X.PP
- XExecutables residing on NFS mounted directores are unpacked to a directory local
- to the system and run from there. These executables lie around for about one
- minute after disuse, after which time they get deleted.
- X.PP
- All this action is transparant to the user, but executables residing on NFS
- mounted filesystems actually get the benefit of not hanging, in the event of
- paging activity, if the NFS server on which they live goes down. This fact
- will also improve the performance of executables on machines short of memory.
- X.SH SEE ALSO
- untcx(1)
- X.SH CAVEATS
- Tcx will try to maintain permissions but in order to allow execution
- of a program on an NFS mounted filesystem to which another machine may
- not have root access to, it also sets the read bits on the executable
- corresponding to the execute bits. This may be a slight security flaw
- and if it causes you problems on particular executables, do not use it on them.
- X.PP
- NFS mounted shell scripts which rely on `dirname $0` being set to something
- meaningful will probably break, as the TCX system can't fool the shell
- with a dummy argv[0] through the exec() call.
- X.PP
- Tcx requires the corresponding untcx(1) program to be available otherwise
- transparency is not assured. Yell at your Systems Programmer if tcx'ed
- executables fail to execute.
- X.SH BUGS
- Tcx is still in beta test stage, so there are bound to be some.
- Please report any bugs or "patch"-style bug fixes (or new system ports)
- or even just suggested improvements, via email to slf@cs.mu.OZ.AU
- X.SH AUTHOR
- Stewart Forster, University Of Melbourne, 1993
- END_OF_FILE
- if test 2208 -ne `wc -c <'tcx.1'`; then
- echo shar: \"'tcx.1'\" unpacked with wrong size!
- fi
- # end of 'tcx.1'
- fi
- if test -f 'tcx.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tcx.c'\"
- else
- echo shar: Extracting \"'tcx.c'\" \(9587 characters\)
- sed "s/^X//" >'tcx.c' <<'END_OF_FILE'
- X/* tcx.c, Version 1.0.4, 1/4/1993 by Stewart Forster */
- X
- X/************************************************************************/
- X/* Copyright (C) 1993 Stewart Forster */
- X/* This program is free software; you can redistribute it and/or modify*/
- X/* it under the terms of the GNU General Public License as published by*/
- X/* the Free Software Foundation; either version 2, or (at your option) */
- X/* any later version. */
- X/* */
- X/* This program is distributed in the hope that it will be useful, */
- X/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
- X/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
- X/* GNU General Public License for more details. */
- X/* */
- X/* You should have received a copy of the GNU General Public License */
- X/* along with this program; if not, write to the Free Software */
- X/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- X/************************************************************************/
- X
- X#include "config.h"
- X
- extern int errno;
- X
- int main(int, char *[]);
- int is_tcx(int);
- int doencode(int, int);
- X
- X#ifdef ULTRIX
- int is_file_local(char *);
- X#endif
- X
- char execname[MAXPATHLEN];
- char execpath[MAXPATHLEN];
- char dofile[MAXPATHLEN];
- char tofile[MAXPATHLEN];
- char header[MAXHEADERSIZE];
- X
- int
- main(int argc, char *argv[])
- X{
- struct stat dostat;
- char *s;
- int perms;
- int infd, outfd;
- int len;
- struct flock lck;
- unsigned char c;
- X#ifdef ULTRIX
- int islocal;
- X#endif
- X
- X /* Check to make sure we have an argument */
- X
- X if(argc < 2)
- X {
- X (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
- X exit(-1);
- X }
- X
- X if(getwd(dofile) == NULL)
- X {
- X (void)fprintf(stderr, "Get Working Directory Error: %s\n", dofile);
- X exit(-1);
- X }
- X
- X if(*argv[1] == '/')
- X (void)strcpy(dofile, argv[1]);
- X else
- X {
- X (void)strcat(dofile, "/");
- X (void)strcat(dofile, argv[1]);
- X }
- X for(;;)
- X {
- X if((s = strrchr(dofile, '/')) == NULL)
- X {
- X (void)fprintf(stderr, "Internal corruption of variables!\n");
- X exit(-1);
- X }
- X s++;
- X (void)strcpy(execname, s);
- X *s = '\0';
- X
- X if(chdir(dofile) < 0) { perror(dofile); exit(-1); }
- X
- X if(getwd(dofile) == NULL)
- X {
- X (void)fprintf(stderr, "Get Working Directory Error: %s\n", dofile);
- X exit(-1);
- X }
- X
- X if(lstat(execname, &dostat) < 0) { perror(execname); exit(-1); }
- X
- X if((dostat.st_mode & S_IFMT) == S_IFLNK)
- X {
- X if((len = readlink(execname, execpath, MAXPATHLEN)) < 0)
- X {
- X perror(execname);
- X exit(-1);
- X }
- X execpath[len] = '\0';
- X if(execpath[0] == '/')
- X (void)strcpy(dofile, execpath);
- X else
- X {
- X (void)strcat(dofile, "/");
- X (void)strcat(dofile, execpath);
- X }
- X continue;
- X }
- X
- X /* If we get here, dofile is no longer pointing at a symlink */
- X
- X (void)strcat(dofile, "/");
- X (void)strcat(dofile, execname);
- X break;
- X }
- X
- X /* dofile from now on is the FULL pathname to the executable we're tcx-ing */
- X
- X /* Just do a normal stat on dofile */
- X
- X if(stat(dofile, &dostat) < 0) { perror(dofile); exit(-1); }
- X
- X /* Make sure it's a regular file. If not, quit! */
- X
- X if(!(dostat.st_mode & S_IFREG))
- X {
- X (void)fprintf(stderr, "Error: %s is not a regular file\n", dofile);
- X exit(-1);
- X }
- X
- X /* Check permissions on file, must not be setuid or setgid */
- X /* Then check to see if it's an executable */
- X
- X if(dostat.st_mode & (S_ISUID | S_ISGID))
- X {
- X (void)fprintf(stderr, "Error: Cannot compress setuid or setgid programs.\n");
- X exit(-1);
- X }
- X
- X if(! (dostat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
- X {
- X (void)fprintf(stderr, "File does have any execute bits set. Aborting.\n");
- X exit(-1);
- X }
- X
- X if(dostat.st_nlink > 1)
- X {
- X (void)fprintf(stderr, "File has multiple hard links to it! These will be destroyed\n");
- X (void)fprintf(stderr, "by this operation. Please turn the hard links into symlinks.\n");
- X exit(-1);
- X }
- X
- X#ifdef ULTRIX
- X /* Test to see if file we are compressing is local or not */
- X
- X if((islocal = is_file_local(dofile)) < 0)
- X {
- X perror("statfs");
- X exit(-1);
- X }
- X#endif
- X
- X /* Now open file we are compressing for reading. Quit if can't. */
- X
- X if((infd = open(dofile, O_RDONLY)) < 0)
- X {
- X perror(dofile);
- X exit(-1);
- X }
- X
- X /* Check to make sure file is not already tcx'ed */
- X
- X if(is_tcx(infd))
- X {
- X (void)fprintf(stderr, "%s is already in tcx format!\n", dofile);
- X exit(0);
- X }
- X
- X if(lseek(infd, 0, SEEK_SET) < 0)
- X {
- X perror("lseek");
- X exit(-1);
- X }
- X
- X /* Open generation file, and try to mimic permissions */
- X /* If cannot, warn user and quit */
- X
- X (void)strcpy(tofile, dofile);
- X s = strrchr(tofile, '/');
- X *s = '\0';
- X (void)strcat(tofile, "/.tcx.");
- X s = strrchr(dofile, '/');
- X s++;
- X (void)strcat(tofile, s);
- X
- X lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X
- X perms = (dostat.st_mode & 0777);
- X if(perms & S_IXUSR) perms |= S_IRUSR;
- X if(perms & S_IXGRP) perms |= S_IRGRP;
- X if(perms & S_IXOTH) perms |= S_IROTH;
- X perms |= S_IWUSR;
- X
- X /* Attempt to create scratch file */
- X /* Ultrix barfs on F_SETLK if file is on an NFS mount. */
- X
- X if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
- X {
- X#ifdef ULTRIX
- X if(islocal == 0 || errno != EEXIST)
- X#else
- X if(errno != EEXIST)
- X#endif
- X {
- X perror(tofile);
- X exit(-1);
- X }
- X
- X /* Attempt to open and lock file that's there. If we can't */
- X /* lock the file, someone else must be packing it, so quit. */
- X /* If we can, it must be bogus and left lying around after a*/
- X /* crash, interrupt or something. Delete file and try again.*/
- X
- X if((outfd = open(tofile, O_WRONLY)) < 0)
- X {
- X perror(tofile);
- X exit(-1);
- X }
- X
- X if(fcntl(outfd, F_SETLK, &lck) < 0)
- X exit(-1);
- X
- X (void)unlink(tofile); /* Unlink. Don't care if fails yet */
- X (void)close(outfd);
- X if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
- X {
- X perror(tofile);
- X exit(-1);
- X }
- X }
- X
- X /* Attempt to lock tofile. If can't then assume someone else */
- X /* is in the process of packing this file, so quit. */
- X /* Only try to lock on ULTRIX if file is local. If not, risk */
- X /* the race condition, we have no choice!. */
- X
- X#ifdef ULTRIX
- X if(islocal == 1)
- X#endif
- X if(fcntl(outfd, F_SETLK, &lck) < 0)
- X exit(-1);
- X
- X /* Do a chmod (Just to be sure - in case of user umask affecting open) */
- X
- X if(chmod(tofile, perms) < 0)
- X {
- X (void)fprintf(stderr, "Cannot set proper permissions on scratch file %s\n", tofile);
- X (void)close(infd);
- X (void)close(outfd);
- X if(unlink(tofile) < 0)
- X (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
- X exit(-1);
- X }
- X
- X if(chown(tofile, dostat.st_uid, dostat.st_gid) < 0)
- X {
- X (void)fprintf(stderr, "Cannot set proper ownership on scratch file\n");
- X (void)close(infd);
- X (void)close(outfd);
- X if(unlink(tofile) < 0)
- X (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
- X exit(-1);
- X }
- X
- X /* Spit out header and start encoding executable */
- X
- X (void)sprintf(header, "#!%s\n", PATHUNTCX);
- X if(write(outfd, header, strlen(header)) < 0) { (void)perror("write"); exit(-1); }
- X
- X c = 0; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
- X c = 76; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
- X c = 193; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
- X c = 13; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
- X c = 138; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
- X
- X if(doencode(infd, outfd) != 0)
- X {
- X (void)fprintf(stderr, "Compression failed\n");
- X if(unlink(tofile) < 0)
- X (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
- X exit(-1);
- X }
- X
- X (void)close(infd);
- X
- X if((infd = open(dofile, O_WRONLY)) <= 0)
- X {
- X perror(dofile);
- X if(unlink(tofile) < 0)
- X (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
- X exit(-1);
- X }
- X
- X#ifdef ULTRIX
- X if(islocal == 1)
- X#endif
- X if(fcntl(infd, F_SETLK, &lck) < 0)
- X {
- X if(unlink(tofile) < 0)
- X (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
- X exit(-1);
- X }
- X
- X /* Rename() compressed version to original */
- X
- X if(rename(tofile, dofile) < 0)
- X {
- X perror(dofile);
- X if(unlink(tofile) < 0)
- X (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
- X exit(-1);
- X }
- X
- X /* Close files and hence locks */
- X
- X (void)close(infd);
- X (void)close(outfd);
- X
- X /* All done! Bye, bye. */
- X
- X return(0);
- X}
- X
- X
- int
- is_tcx(int fd)
- X{
- int i;
- unsigned char c;
- X
- X for(i = 0; i < MAXHEADERSIZE; i++)
- X if(read(fd, &c, 1) < 1 || c == 0)
- X break;
- X if((i >= MAXHEADERSIZE) || read(fd, &c, 1) < 1 || c != 76 || read(fd, &c, 1) < 1 || c != 193
- X || read(fd, &c, 1) < 1 || c != 13 || read(fd, &c, 1) < 1 || c != 138 )
- X return 0;
- X return 1;
- X} /* is_tcx */
- X
- X
- int
- doencode(int infd, int outfd)
- X{
- int pid;
- X#if defined(AIX) || defined(IRIX)
- int status;
- X#else
- union wait status;
- X#endif
- X
- X pid = fork();
- X if(pid < 0) return -1;
- X if(pid == 0)
- X {
- X if(dup2(infd, 0) < 0) exit(-1); /* Attach infd to stdin */
- X (void)close(infd);
- X if(dup2(outfd, 1) < 0) exit(-1); /* Attach outfd to stdout */
- X (void)close(outfd);
- X#ifdef PACKEROPTS
- X (void)execl(PATHPACKER, PATHPACKER, PACKEROPTS, (char *)0);
- X#else
- X (void)execl(PATHPACKER, PATHPACKER, (char *)0);
- X#endif
- X exit(-1);
- X }
- X else
- X pid = wait(&status);
- X return WEXITSTATUS(status);
- X} /* doencode */
- X
- X
- X#ifdef ULTRIX
- int
- is_file_local(char *path)
- X{
- struct fs_data fsbuf;
- X
- X if(statfs(path, &fsbuf) < 1) /* Returns 0 on "NOT MOUNTED" */
- X return -1;
- X
- X /* NFS Version 2 returns -1 or 0 for both gfree, and gtot */
- X /* to a client, so return false on this condition. */
- X
- X if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
- X return 0;
- X return 1;
- X} /* is_file_local */
- X#endif
- END_OF_FILE
- if test 9587 -ne `wc -c <'tcx.c'`; then
- echo shar: \"'tcx.c'\" unpacked with wrong size!
- fi
- # end of 'tcx.c'
- fi
- if test -f 'untcx.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'untcx.1'\"
- else
- echo shar: Extracting \"'untcx.1'\" \(1639 characters\)
- sed "s/^X//" >'untcx.1' <<'END_OF_FILE'
- X.TH UNTCX 1 "19 March 1993"
- X.UC Melb
- X.SH NAME
- untcx \- Uncompress or execute tcx executables
- X.SH SYNOPSIS
- untcx [-x | -u] filename [args]
- X.SH DESCRIPTION
- X\fBUntcx\fP performs three functions. Firstly used as listed above, it
- will uncompress an executable compressed with tcx(1), if such compression
- is no longer desired. If the \fB-x\fP option is specified, this will force
- untcx to execute \fBfilename\fP, with \fBargs\fP as command line arguments.
- X.PP
- If the \fB-u\fP option is given, this forces untcx into plain decompression
- of \fBfilename\fP. Note, that while this is the default mode of operation for
- users other than root, it is required if the invoking user is root. Under the
- LINUX operating system, the -u option is ALWAYS required by any user if that
- user wishes to explicitly uncompress an executable.
- X.PP
- Secondly it is the tool which performs and transparant uncompression
- and execution of executables compressed with tcx(1). This mode of
- operation is never directly seen by the user (otherwise it wouldn't
- be transparent would it!).
- X.PP
- Thirdly it invokes itself in a daemon mode which will keep track of
- all executables operating withing the tcx system, to allow for
- transparent recompression of executables that have been uncompressed
- in the process of being invoked. This mode of operation is also
- transparent to the user.
- X.SH SEE ALSO
- tcx(1)
- X.SH BUGS
- Untcx is still in beta test stage, so there are bound to be some.
- Please report any bugs or "patch"-style bug fixes (or new system ports)
- or even just suggested improvements, via email to slf@cs.mu.OZ.AU
- X.SH AUTHOR
- Stewart Forster, University Of Melbourne, 1993
- END_OF_FILE
- if test 1639 -ne `wc -c <'untcx.1'`; then
- echo shar: \"'untcx.1'\" unpacked with wrong size!
- fi
- # end of 'untcx.1'
- fi
- if test -f 'untcx.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'untcx.c'\"
- else
- echo shar: Extracting \"'untcx.c'\" \(31646 characters\)
- sed "s/^X//" >'untcx.c' <<'END_OF_FILE'
- X/* untcx.c, Version 1.0.5, 5/4/1993 by Stewart Forster */
- X
- X/************************************************************************/
- X/* Copyright (C) 1993 Stewart Forster */
- X/* This program is free software; you can redistribute it and/or modify*/
- X/* it under the terms of the GNU General Public License as published by*/
- X/* the Free Software Foundation; either version 2, or (at your option) */
- X/* any later version. */
- X/* */
- X/* This program is distributed in the hope that it will be useful, */
- X/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
- X/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
- X/* GNU General Public License for more details. */
- X/* */
- X/* You should have received a copy of the GNU General Public License */
- X/* along with this program; if not, write to the Free Software */
- X/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- X/************************************************************************/
- X
- X#include "config.h"
- X
- typedef struct path
- X{
- X char path[MAXPATHLEN]; /* Pathname to file */
- X#ifdef UNPACK_IN_PLACE
- X int pid; /* Process id compressing file */
- X int local; /* Is file local? */
- X#endif
- X int atime; /* Time last known to be busy */
- X int ctime; /* Inode modification time */
- X struct path *next; /* Next structure */
- X} path;
- X
- X#if defined(SUNOS)
- X#define MAXOPENFILES 4096
- X#define PIHASH(a, b) (((a) + (b)) % MAXOPENFILES)
- X
- typedef struct pstat
- X{
- X int dev;
- X int ino;
- X int cnt;
- X struct pstat *next;
- X} pstat;
- X
- pstat parr[MAXOPENFILES];
- pstat *pihash[MAXOPENFILES];
- void update_pstat_info();
- X#endif
- X
- extern int errno;
- path *worklist = NULL, *freelist = NULL;
- X
- X
- char logpath[MAXPATHLEN], logtmppath[MAXPATHLEN], lockpath[MAXPATHLEN];
- X
- char cwd[MAXPATHLEN]; /* Save of current working directory */
- char realdir[MAXPATHLEN]; /* Real directory packed executable lives in */
- char execname[MAXPATHLEN]; /* Name of packed/target executable */
- char execpath[MAXPATHLEN]; /* Full path name of packed executable */
- char untcxtmp[MAXPATHLEN]; /* Temporary unpack pathname */
- char tcxtarg[MAXPATHLEN]; /* Target path name of unpacked executable */
- char linkpath[MAXPATHLEN]; /* Pathname of symlink to executable */
- X
- void untcx_and_exec_local(char *, char *, char *[]);
- void untcx_and_exec_nfs(char *, char *, char *, char *[]);
- int try_to_exec(char *, char *, char *[]);
- void check_tcxd_mode();
- X#ifdef UNPACK_IN_PLACE
- SIGTYPE tcxd_reaper();
- X#endif
- void just_untcx(char *, char *);
- int scan_logtail(int);
- int is_dir_local(char *);
- int is_tcx(int);
- int dodecode(int, int);
- char *newargs[1024];
- X#if defined(ULTRIX)
- int usleep(int);
- int usleep_sig();
- X#endif
- X
- int
- main(int argc, char *argv[])
- X{
- char *c; /* String manipulation pointers */
- struct stat dostat; /* Stat buffer */
- int i, isinterp, len;
- X#ifdef UNPACK_IN_PLACE
- int local;
- X#endif
- X
- X if(argc < 2)
- X {
- X (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
- X exit(-1);
- X }
- X
- X /* Re-exec if not root and pass -x along on the command line. */
- X /* If it's there when we restart and we're still not root, then */
- X /* avoid an exec loop by quitting with a warning. */
- X
- X if(geteuid() != 0)
- X {
- X#ifndef LINUX
- X if(strcmp(argv[1], "-x") == 0)
- X#endif
- X {
- X (void)fprintf(stderr, "Error: untcx is not installed setuid to root!\n");
- X (void)fprintf(stderr, "Contact your systems administrator\n");
- X exit(-1);
- X }
- X
- X /* Push -x into argv[1] and shift rest of args along */
- X
- X newargs[0] = argv[0];
- X newargs[1] = "-x";
- X for(i = 1; i < argc; i++) newargs[i+1] = argv[i];
- X newargs[i + 1] = (char *)NULL;
- X if(execv(PATHUNTCX, newargs) < 0)
- X perror("exec");
- X
- X /* exec failed! Warn user and quit */
- X
- X (void)fprintf(stderr, "Unable to invoke interpreter as root\n");
- X exit(-1);
- X }
- X
- X if(strcmp(argv[1], "-x") == 0)
- X {
- X for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
- X argv[i] = (char *)NULL;
- X --argc;
- X isinterp = 1;
- X }
- X else
- X if(strcmp(argv[1], "-u") == 0)
- X {
- X for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
- X argv[i] = (char *)NULL;
- X --argc;
- X isinterp = 0;
- X }
- X else
- X#if defined(LINUX)
- X isinterp = 1;
- X#else
- X if(getuid() == 0)
- X isinterp = 1;
- X else
- X isinterp = 0;
- X#endif
- X
- X /* Copy argv[1] to argv[0] for obsolete stuff (and IRIX) */
- X
- X argv[0] = argv[1];
- X
- X /* Setup to catch all undesirable signals */
- X
- X (void)signal(SIGINT, SIG_IGN);
- X (void)signal(SIGHUP, SIG_IGN);
- X (void)signal(SIGTSTP, SIG_IGN);
- X (void)signal(SIGALRM, SIG_IGN);
- X (void)signal(SIGQUIT, SIG_IGN);
- X (void)signal(SIGTERM, SIG_IGN);
- X
- X /* Set global paths */
- X
- X (void)sprintf(logpath, "%s/log", ENFSDIR);
- X (void)sprintf(logtmppath, "%s/logtmp", ENFSDIR);
- X (void)sprintf(lockpath, "%s/.lock", ENFSDIR);
- X
- X /* Check and start tcxd as required */
- X
- X check_tcxd_mode();
- X
- X /* Go to the uid of invoking user. Resolve through symbolic links */
- X /* as to what the real pathname of the executable is. */
- X
- X#ifdef AIX
- X if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
- X#else
- X if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X
- X /* Grab argv[0] and resolve to full path name via getwd() */
- X
- X if(getwd(cwd) == NULL)
- X {
- X (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
- X exit(-1);
- X }
- X
- X if(*argv[0] == '/')
- X (void)strcpy(realdir, argv[0]);
- X else
- X (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
- X for(;;)
- X {
- X if((c = strrchr(realdir, '/')) == NULL)
- X { /* Should never happen, BUT... */
- X (void)fprintf(stderr, "Help! Internal corruption of variables!\n");
- X exit(-1);
- X }
- X c++;
- X (void)strcpy(execname, c);
- X *c = '\0';
- X
- X if(chdir(realdir) < 0) /* Oops. Failed. Report and quit. */
- X {
- X perror(realdir);
- X exit(-1);
- X }
- X
- X if(getwd(realdir) == NULL)
- X {
- X (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
- X exit(-1);
- X }
- X
- X /* Do lstat executable from here. If not a link, go on, else */
- X /* read the value of the link, and append it to realdir if */
- X /* it doesn't begin with a /, other just copy it to realdir */
- X /* and cycle through the loop again. */
- X
- X if(lstat(execname, &dostat) < 0)
- X {
- X perror(execname);
- X exit(-1);
- X }
- X
- X if((dostat.st_mode & S_IFMT) == S_IFLNK)
- X {
- X if((len = readlink(execname, execpath, MAXPATHLEN)) < 0)
- X {
- X perror(execname);
- X exit(-1);
- X }
- X execpath[len] = '\0';
- X if(execpath[0] == '/')
- X (void)strcpy(realdir, execpath);
- X else
- X {
- X (void)strcat(realdir, "/");
- X (void)strcat(realdir, execpath);
- X }
- X continue;
- X }
- X
- X if(!(dostat.st_mode & S_IFREG))
- X {
- X (void)fprintf(stderr, "Error: Not an executable file - %s/%s\n", realdir, execname);
- X exit(-1);
- X }
- X
- X /* Now do a statfs on realdir. If it's on an NFS mounted filesystem we */
- X /* will need to unpack to ENFSDIR, otherwise we can unpack it in place, */
- X
- X#ifdef UNPACK_IN_PLACE
- X if((local = is_dir_local(realdir)) < 0)
- X exit(-1);
- X if(dostat.st_nlink > 1) /* Unpack to ENFSDIR if file is linked */
- X local = 0;
- X#endif
- X
- X break;
- X }
- X
- X /* Return to the original invocation directory */
- X
- X if(chdir(cwd) < 0)
- X {
- X perror(cwd);
- X exit(-1);
- X }
- X
- X#ifdef AIX
- X if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
- X#else
- X if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X
- X /* Now check if last components of argv[0] and argv[1] are equal */
- X /* If not, we are invoked just to decompress something, not to */
- X /* execute it. Just attempt an uncompress as the user */
- X
- X if(isinterp == 0)
- X {
- X#if defined(IRIX) || defined(AIX)
- X if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
- X#else
- X if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
- X (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
- X just_untcx(tcxtarg, untcxtmp);
- X exit(0);
- X }
- X
- X#ifdef UNPACK_IN_PLACE
- X /* Try to do a local execute. If it returns, it means failure. */
- X
- X if(local)
- X {
- X (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
- X (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
- X untcx_and_exec_local(tcxtarg, untcxtmp, &(argv[1]));
- X }
- X#endif
- X
- X /* We get this far if file is not local, or the local execution */
- X /* failed for some reason like shortage of disk space. Attempt */
- X /* to unpack program to /tmp and go from there. */
- X
- X for(c = realdir; *c ; c++)
- X if(*c == '/')
- X *c = '=';
- X (void)sprintf(tcxtarg, "%s/%s", ENFSDIR, realdir);
- X if(mkdir(tcxtarg, 0777) < 0)
- X if(errno != EEXIST)
- X {
- X perror(tcxtarg);
- X exit(-1);
- X }
- X (void)chmod(tcxtarg, 0777);
- X (void)strcat(tcxtarg,"/");
- X (void)strcat(tcxtarg, execname);
- X (void)sprintf(untcxtmp, "%s/%s/.untcx.%s", ENFSDIR, realdir, execname);
- X
- X untcx_and_exec_nfs(argv[0], untcxtmp, tcxtarg, &(argv[1]));
- X
- X /* :-( We only get this far if everything has failed. Exit with failure */
- X
- X return(-1);
- X} /* main */
- X
- X
- void
- check_tcxd_mode()
- X{
- char *s, spid[32];
- int infd, logfd, lkfd, lasttime = 0, timer;
- XFILE *logfp;
- path *curr, *prev;
- struct stat sb; /* Stat buffer */
- struct flock lck; /* File lock structure */
- int lastoff;
- X
- X /* Check if we're root. If not, go home */
- X
- X if(geteuid() != 0)
- X return;
- X
- X /* Try to create emergency/NFS execute directory and set it's permissions */
- X /* It's not important yet if we can't at this stage. */
- X
- X (void)mkdir(ENFSDIR, 01777);
- X (void)chmod(ENFSDIR, 01777);
- X
- X /* Attempt to create ENFSDIR/.lock If can't, just return. */
- X
- X if((lkfd = open(lockpath, O_CREAT | O_RDONLY, 0600)) < 0)
- X return;
- X
- X /* Attempt to read lock ENFSDIR/.lock If can't, we assume the tcxd */
- X /* is already running. Return. */
- X
- X lck.l_type = F_RDLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X if(fcntl(lkfd, F_SETLK, &lck) < 0)
- X {
- X (void)close(lkfd);
- X return;
- X }
- X
- X /* Close lkfd and hence the lock on it, fork() and return */
- X
- X (void)close(lkfd);
- X if(fork() != 0) /* On parent or fork error, just return */
- X return;
- X
- X /* No errors to user at this point */
- X
- X (void)fclose(stderr); (void)close(2);
- X (void)fclose(stdout); (void)close(1);
- X (void)open("/dev/null", O_WRONLY);
- X (void)open("/dev/null", O_WRONLY); /* Don't really care */
- X
- X /* Make ourselves nice and rooted */
- X
- X#ifndef AIX
- X#if defined(IRIX)
- X if(setuid(geteuid()) < 0) exit(-1);
- X#else
- X if(setreuid(geteuid(), geteuid()) < 0) exit(-1);
- X#endif
- X#endif
- X
- X /* Check if we're root again. If not, exit */
- X
- X if(geteuid() != 0)
- X exit(-1);
- X
- X /* Change directory to ENFSDIR to prevent hanging on NFS server crashes */
- X
- X if(chdir(ENFSDIR) < 0)
- X exit(-1);
- X
- X /* Lock the server lock file to prevent more than 1 starting up */
- X
- X if((lkfd = open(lockpath, O_WRONLY | O_TRUNC)) < 0)
- X exit(-1);
- X lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X if(fcntl(lkfd, F_SETLK, &lck) < 0)
- X exit(-1);
- X
- X /* Write our process id to the lock file. Don't really care if fails. */
- X
- X (void)sprintf(spid, "%d\n", getpid());
- X (void)write(lkfd, spid, strlen(spid));
- X
- X#ifdef UNPACK_IN_PLACE
- X /* setup our child process reaper */
- X
- X (void)signal(SIGCHLD, tcxd_reaper);
- X#endif
- X
- X /* Read in log file if it's there in case of crashes */
- X
- X if((lastoff = scan_logtail(0)) < 0)
- X (void)creat(logpath, 0600);
- X
- X /* Loop doing tasks at hand */
- X
- X for(lastoff = 0;;)
- X {
- X for(timer = 0; timer < SCANRATE; timer++, (void)sleep(1))
- X {
- X if(stat(logpath, &sb) < 0)
- X continue;
- X
- X /* Don't check if not updated, but do on last time */
- X
- X if(sb.st_mtime <= lasttime)
- X continue;
- X lasttime = sb.st_mtime;
- X
- X lastoff = scan_logtail(lastoff);
- X }
- X
- X#if defined(SUNOS)
- X update_pstat_info();
- X#endif
- X
- X for(prev = NULL, curr = worklist; curr != NULL; prev = curr, curr = curr->next)
- X {
- X /* Stat file. If not accessed within LOCALTIMOUT secs */
- X /* for a local file, or ENFSTIMEOUT secs for an NFS file */
- X /* we consider it a candidate for compression. */
- X
- X if(stat(curr->path, &sb) < 0)
- X {
- X if(lstat(curr->path, &sb) >= 0)
- X {
- X (void)unlink(curr->path); /* Was symlink. Unlink it! */
- X s = strrchr(curr->path, '/');
- X *s = '\0';
- X (void)rmdir(curr->path);
- X }
- X (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
- X curr->next = freelist; freelist = curr;
- X (prev == NULL) ? (curr = worklist) : (curr = prev);
- X if(curr == NULL) break;
- X continue;
- X }
- X
- X if(sb.st_atime > curr->atime)
- X curr->atime = sb.st_atime;
- X
- X#ifdef UNPACK_IN_PLACE
- X if(curr->local == 1 && (time(NULL) - curr->atime) < LOCALTIMEOUT)
- X continue;
- X if(curr->local == 0 && (time(NULL) - curr->atime) < ENFSTIMEOUT)
- X continue;
- X#else
- X if((time(NULL) - curr->atime) < ENFSTIMEOUT)
- X continue;
- X#endif
- X
- X#if defined(IRIX) || defined(DEC) || defined(AIX) || defined(LINUX)
- X /* Attempt to open file for writing, if it fails with ETXTBSY */
- X /* then update access times and continue, otherwise it is a */
- X /* candidate for recompression. */
- X
- X if((infd = open(curr->path, O_WRONLY)) < 0)
- X {
- X if(errno != ETXTBSY)
- X {
- X if(lstat(curr->path, &sb) >= 0)
- X {
- X (void)unlink(curr->path); /* Was symlink. Unlink it! */
- X s = strrchr(curr->path, '/');
- X *s = '\0';
- X (void)rmdir(curr->path);
- X }
- X (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
- X curr->next = freelist; freelist = curr;
- X (prev == NULL) ? (curr = worklist) : (curr = prev);
- X if(curr == NULL) break;
- X continue;
- X }
- X curr->atime = time(NULL);
- X continue;
- X }
- X (void)close(infd);
- X#endif
- X
- X#if defined(SUNOS)
- X {
- X pstat *pc;
- X int found = 0;
- X
- X for(pc = pihash[PIHASH(sb.st_dev, sb.st_ino)]; pc != NULL; pc = pc->next)
- X if(pc->dev == sb.st_dev && pc->ino == sb.st_ino)
- X {
- X if(pc->cnt < 2) break;
- X curr->atime = time(NULL);
- X found = 1;
- X break;
- X }
- X if(found) continue;
- X }
- X#endif
- X
- X#ifdef UNPACK_IN_PLACE
- X if(curr->local == -1) /* Compression completed */
- X {
- X (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
- X curr->next = freelist; freelist = curr;
- X (prev == NULL) ? (curr = worklist) : (curr = prev);
- X if(curr == NULL) break;
- X continue;
- X }
- X
- X if(curr->pid > 0)
- X continue;
- X
- X if(curr->local == 1)
- X {
- X /* Check inode modification times. If target is */
- X /* newer than what we know, forget it. */
- X
- X if(sb.st_ctime > curr->ctime)
- X {
- X (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
- X curr->next = freelist; freelist = curr;
- X (prev == NULL) ? (curr = worklist) : (curr = prev);
- X if(curr == NULL) break;
- X continue;
- X }
- X
- X /* Fork and compress program */
- X
- X curr->pid = fork();
- X if(curr->pid != 0) continue;
- X
- X /* Here we must be the child */
- X /* Close stdio stuff and reopen to /dev/null */
- X
- X (void)close(2);
- X (void)close(1);
- X (void)close(0);
- X (void)open("/dev/null", O_RDONLY);
- X (void)open("/dev/null", O_WRONLY);
- X (void)open("/dev/null", O_WRONLY);
- X (void)execl(PATHTCX, "tcx", curr->path, (char *)0);
- X exit(-1);
- X }
- X#endif
- X
- X /* At this point, file is in ENFSDIR. Delete it */
- X
- X (void)unlink(curr->path);
- X s = strrchr(curr->path, '/');
- X *s = '\0';
- X (void)rmdir(curr->path);
- X
- X (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
- X curr->next = freelist; freelist = curr;
- X (prev == NULL) ? (curr = worklist) : (curr = prev);
- X if(curr == NULL) break;
- X } /* for */
- X
- X /* Update log file in case of crashes */
- X
- X lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X
- X /* Do one final read in case someone has modified during */
- X /* the scan sequence. */
- X
- X (void)scan_logtail(lastoff);
- X
- X if((logfp = fopen(logtmppath, "w")) == NULL)
- X continue;
- X for(curr = worklist; curr != NULL; curr = curr->next)
- X (void)fprintf(logfp, "%s\n", curr->path);
- X (void)fclose(logfp);
- X
- X /* Try for 20 times to lock file, sleep 5/100ths secs b/w tries */
- X
- X for(timer = 0; timer < 20; timer++, PUSLEEP(50000))
- X {
- X if((logfd = open(logpath, O_WRONLY)) < 0)
- X continue;
- X if(fcntl(logfd, F_SETLK, &lck) < 0)
- X { (void)close(logfd); continue; }
- X
- X (void)rename(logtmppath, logpath);
- X if(stat(logpath, &sb) < 0)
- X lastoff = 0;
- X else
- X lastoff = sb.st_size;
- X (void)close(logfd);
- X break;
- X }
- X } /* for */
- X} /* check_tcxd_mode */
- X
- X
- X#ifdef UNPACK_IN_PLACE
- SIGTYPE
- tcxd_reaper()
- X{
- X#if defined(AIX)
- int state;
- X#else
- union wait state;
- X#endif
- int pid;
- path *curr;
- X
- X while((pid = wait3(&state, WNOHANG, 0)) > 0)
- X for(curr = worklist; curr != NULL; curr = curr->next)
- X if(curr->pid == pid)
- X {
- X curr->pid = -1;
- X if(WIFEXITED(state) && WEXITSTATUS(state) == 0)
- X curr->local = -1;
- X break;
- X }
- X#if defined(IRIX) || defined(AIX)
- X (void)signal(SIGCHLD, tcxd_reaper);
- X#endif
- X} /* tcxd_reaper */
- X#endif
- X
- X
- X#ifdef UNPACK_IN_PLACE
- void
- untcx_and_exec_local(char *expath, char *untemp, char *argv[])
- X{
- struct stat tostat; /* Stat buffer to check on lengths */
- int owner, group;
- int perms; /* Saved permissions to restore on target exec */
- int infd, outfd; /* In and out file descriptors */
- struct flock lck; /* File lock structure */
- X
- X /* In this function argv[0] and expath would normally be the same */
- X /* BUT, if argv[0] is a symlink to expath, we want to invoke it */
- X /* like that, and not via expath. */
- X
- X /* Stat executable and grab permissions */
- X
- X if(stat(expath, &tostat) < 0)
- X {
- X perror(argv[0]);
- X exit(-1);
- X }
- X perms = (tostat.st_mode & 0777);
- X owner = tostat.st_uid;
- X group = tostat.st_gid;
- X
- X for(;;PUSLEEP(10000))
- X {
- X if((infd = open(expath, O_RDWR)) < 0)
- X {
- X if(errno != ETXTBSY)
- X {
- X (void)fprintf(stderr, "Cannot write to %s\n", expath);
- X exit(-1);
- X }
- X if((infd = open(expath, O_RDONLY)) < 0)
- X continue;
- X (void)close(infd);
- X if(try_to_exec(expath, argv[0], argv) < 0)
- X exit(-1);
- X continue;
- X }
- X
- X lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X if(fcntl(infd, F_SETLK, &lck) < 0)
- X {
- X if(fcntl(infd, F_GETLK, &lck) < 0 || lck.l_type != F_RDLCK)
- X { (void)close(infd); continue; }
- X (void)close(infd);
- X if(try_to_exec(expath, argv[0], argv) < 0)
- X exit(-1);
- X continue;
- X }
- X
- X if(! is_tcx(infd))
- X {
- X (void)close(infd);
- X if(try_to_exec(expath, argv[0], argv) < 0)
- X exit(-1);
- X continue;
- X }
- X
- X /* File is in packed format. Unpack it */
- X
- X if((outfd = open(untemp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
- X {
- X if(errno != EEXIST)
- X {
- X perror(untemp);
- X exit(-1);
- X }
- X if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
- X {
- X perror(untemp);
- X exit(-1);
- X }
- X }
- X
- X /* Start decompressing executable */
- X
- X if(dodecode(infd, outfd) != 0)
- X {
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X (void)close(outfd);
- X
- X /* Now set execute permissions on the beastie */
- X
- X if(chmod(untemp, perms) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X if(chown(untemp, owner, group) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X /* Rename untemporary file to target executable and close target */
- X
- X if(rename(untemp, expath) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X (void)close(infd);
- X
- X /* Everything OK! Now go exec the executable. */
- X
- X if(try_to_exec(expath, argv[0], argv) < 0)
- X exit(-1);
- X } /* for */
- X} /* untcx_and_exec_local */
- X#endif
- X
- X
- void
- untcx_and_exec_nfs(char *expath, char *untemp, char *targ, char *argv[])
- X{
- struct stat tostat; /* Stat buffer to check on lengths */
- int mtime;
- int owner, group;
- int perms; /* Saved permissions to restore on target exec */
- int infd, outfd; /* In and out file descriptors */
- struct flock lck; /* File lock structure */
- char *c;
- int len;
- X
- X /* Stat executable and grab permissions */
- X
- X#ifdef AIX
- X if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
- X#else
- X if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X
- X if(stat(expath, &tostat) < 0) { perror(argv[0]); exit(-1); }
- X
- X perms = (tostat.st_mode & 0777);
- X mtime = tostat.st_mtime;
- X owner = tostat.st_uid;
- X group = tostat.st_gid;
- X
- X /* resolve first stage of argv[0] */
- X
- X if(getwd(cwd) == NULL) { (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd); exit(-1); }
- X
- X if(*argv[0] == '/') (void)strcpy(realdir, argv[0]); else (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
- X
- X if((c = strrchr(realdir, '/')) == NULL) { (void)fprintf(stderr, "Help! Internal corruption of variables!\n"); exit(-1); }
- X
- X c++; (void)strcpy(execname, c); *c = '\0';
- X
- X if(chdir(realdir) < 0) { perror(realdir); exit(-1); }
- X
- X if(getwd(realdir) == NULL) { (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd); exit(-1); }
- X
- X for(c = realdir; *c; c++)
- X if(*c == '/')
- X *c = '=';
- X (void)sprintf(linkpath, "%s/%s", ENFSDIR, realdir);
- X if(mkdir(linkpath, 0777) < 0)
- X {
- X if(errno != EEXIST) { perror(linkpath); exit(-1); }
- X }
- X else
- X (void)chmod(linkpath, 0777);
- X (void)strcat(linkpath,"/");
- X (void)strcat(linkpath, execname);
- X
- X if(chdir(cwd) < 0) { perror(cwd); exit(-1); }
- X
- X#ifdef AIX
- X if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
- X#else
- X if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X
- X /* Statistics done! Now try to unpack and run it! */
- X
- X for(;;PUSLEEP(10000))
- X {
- X if(stat(targ, &tostat) >= 0)
- X {
- X if(mtime > tostat.st_mtime)
- X {
- X if(strcmp(linkpath, targ) == 0)
- X (void)unlink(linkpath);
- X (void)unlink(targ);
- X }
- X else
- X {
- X if(strcmp(linkpath, targ) == 0)
- X {
- X if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
- X }
- X else
- X if((len = readlink(linkpath, realdir, MAXPATHLEN)) >= 0 && strncmp(realdir, targ, len) == 0)
- X {
- X if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
- X }
- X else
- X {
- X (void)unlink(linkpath);
- X
- X if(symlink(targ, linkpath) < 0) { perror(linkpath); exit(-1); }
- X
- X if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
- X }
- X }
- X }
- X else
- X {
- X /* If symlink to file is there, then get rid of it! */
- X
- X if((len = readlink(linkpath, realdir, MAXPATHLEN)) >= 0 && strncmp(realdir, targ, len) == 0)
- X (void)unlink(linkpath);
- X }
- X
- X#ifdef AIX
- X if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
- X#else
- X if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X if((infd = open(expath, O_RDONLY)) < 0)
- X {
- X perror(expath);
- X exit(-1);
- X }
- X#ifdef AIX
- X if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
- X#else
- X if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X
- X if(! is_tcx(infd))
- X {
- X (void)close(infd);
- X if(try_to_exec(expath, argv[0], argv) < 0)
- X exit(-1);
- X continue;
- X }
- X
- X /* File is in packed format. Unpack it */
- X
- X if((outfd = open(untemp, O_EXCL | O_CREAT | O_WRONLY)) < 0)
- X {
- X if(errno != EEXIST)
- X {
- X perror(untemp);
- X exit(-1);
- X }
- X if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
- X {
- X perror(untemp);
- X exit(-1);
- X }
- X }
- X
- X lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X if(fcntl(outfd, F_SETLK, &lck) < 0)
- X {
- X (void)close(infd);
- X (void)close(outfd);
- X continue;
- X }
- X
- X /* Start decompressing executable */
- X
- X if(dodecode(infd, outfd) != 0)
- X {
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X (void)close(infd);
- X
- X /* Now set execute permissions on the beastie */
- X
- X if(chmod(untemp, perms) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X if(chown(untemp, owner, group) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X /* Rename untemporary file to target executable and close target */
- X
- X if(rename(untemp, targ) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X (void)close(outfd);
- X
- X /* Now create symlink from linkpath to targ if they are not equal */
- X
- X if(strcmp(linkpath, targ) != 0 && symlink(targ, linkpath) < 0)
- X {
- X perror(linkpath);
- X exit(-1);
- X }
- X
- X /* Everything OK! Now go exec the executable. */
- X
- X if(try_to_exec(targ, linkpath, argv) < 0)
- X exit(-1);
- X } /* for */
- X} /* untcx_and_exec_nfs */
- X
- X
- void
- just_untcx(char *expath, char *untemp)
- X{
- struct stat tostat; /* Stat buffer to check on lengths */
- int owner, group;
- int perms; /* Saved permissions to restore on target exec */
- int infd, outfd; /* In and out file descriptors */
- struct flock lck; /* File lock structure */
- X
- X /* Stat executable and grab permissions */
- X
- X if(stat(expath, &tostat) < 0)
- X {
- X perror(expath);
- X exit(-1);
- X }
- X perms = (tostat.st_mode & 0777);
- X owner = tostat.st_uid;
- X group = tostat.st_gid;
- X
- X if((infd = open(expath, O_RDWR)) < 0)
- X {
- X perror(expath);
- X exit(-1);
- X }
- X
- X lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X if(fcntl(infd, F_SETLK, &lck) < 0)
- X {
- X perror(expath);
- X exit(-1);
- X }
- X
- X if(! is_tcx(infd))
- X {
- X (void)fprintf(stderr, "File does not appear to be in tcx format. Aborting\n");
- X exit(-1);
- X }
- X
- X /* File is in packed format. Unpack it */
- X
- X if((outfd = open(untemp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
- X {
- X if(errno != EEXIST)
- X {
- X perror(untemp);
- X exit(-1);
- X }
- X if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
- X {
- X perror(untemp);
- X exit(-1);
- X }
- X }
- X
- X /* Start decompressing executable */
- X
- X if(dodecode(infd, outfd) != 0)
- X {
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X (void)close(outfd);
- X
- X /* Now set execute permissions on the beastie */
- X
- X if(chmod(untemp, perms) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X if(chown(untemp, owner, group) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X /* Rename untemporary file to target executable and close target */
- X
- X if(rename(untemp, expath) < 0)
- X {
- X perror(untemp);
- X if(unlink(untemp) < 0)
- X perror(untemp);
- X exit(-1);
- X }
- X
- X (void)close(infd);
- X return;
- X} /* just_untcx */
- X
- X
- int
- try_to_exec(char *expath, char *lnpath, char *argv[])
- X{
- int infd, try;
- int logfd;
- XFILE *logfp;
- struct flock lck;
- X
- X if((infd = open(lnpath, O_RDONLY)) < 0)
- X {
- X if(errno == ENOENT)
- X {
- X perror(lnpath);
- X return -1;
- X }
- X return 0;
- X }
- X
- X if(is_tcx(infd))
- X {
- X (void)close(infd);
- X return 0;
- X }
- X
- X lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
- X for(try = 0; try < 10; try++, PUSLEEP(50000))
- X {
- X if((logfd = open(logpath, O_WRONLY)) < 0)
- X continue;
- X if(fcntl(logfd, F_SETLK, &lck) < 0)
- X {
- X (void)close(logfd);
- X continue;
- X }
- X
- X if((logfp = fopen(logpath, "a+")) == NULL)
- X {
- X (void)close(logfd);
- X continue;
- X }
- X
- X#ifdef UNPACK_IN_PLACE
- X (void)fprintf(logfp, "%s\n", expath);
- X#else
- X if(strstr(expath, ENFSDIR) == expath)
- X (void)fprintf(logfp, "%s\n", expath);
- X#endif
- X if((strstr(lnpath, ENFSDIR) == lnpath) && (strcmp(lnpath, expath) != 0))
- X (void)fprintf(logfp, "%s\n", lnpath);
- X (void)fclose(logfp);
- X (void)close(logfd);
- X break;
- X }
- X
- X#if defined(IRIX) || defined(AIX)
- X if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
- X#else
- X if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
- X#endif
- X
- X /* Reset signals back to normal to prevent carriage through execv */
- X
- X (void)signal(SIGINT, SIG_DFL);
- X (void)signal(SIGHUP, SIG_DFL);
- X (void)signal(SIGTSTP, SIG_DFL);
- X (void)signal(SIGALRM, SIG_DFL);
- X (void)signal(SIGQUIT, SIG_DFL);
- X (void)signal(SIGTERM, SIG_DFL);
- X
- X (void)close(infd);
- X if(execv(lnpath, argv) < 0)
- X perror(lnpath);
- X return -1;
- X} /* try_to_exec */
- X
- X
- X#if defined(SUNOS)
- void
- update_pstat_info()
- X{
- XFILE *fp;
- char line[256], tmp[10];
- pstat *curr;
- int i, pos;
- int maj, min, dev, ino, cnt;
- X
- X for(pos = 0 ; pos < MAXOPENFILES; pos++)
- X pihash[pos] = (pstat *)NULL;
- X
- X if((fp = popen(PSTATI, "r")) == NULL)
- X return;
- X if(fgets(line, 256, fp) == NULL)
- X return;
- X for(i = 0; fgets(line, 256, fp) != NULL && i < MAXOPENFILES; i++)
- X {
- X curr = parr + i;
- X strncpy(tmp, line+16, 3); tmp[3] = '\0'; maj = atoi(tmp);
- X strncpy(tmp, line+20, 3); tmp[3] = '\0'; min = atoi(tmp);
- X strncpy(tmp, line+23, 6); tmp[6] = '\0'; ino = atoi(tmp);
- X strncpy(tmp, line+61, 4); tmp[4] = '\0'; cnt = atoi(tmp);
- X dev = maj * 256 + min;
- X pos = PIHASH(dev, ino);
- X curr->dev = dev;
- X curr->ino = ino;
- X curr->cnt = cnt;
- X curr->next = pihash[pos];
- X pihash[pos] = curr;
- X } /* while */
- X pclose(fp);
- X} /* update_pstat_info */
- X#endif
- X
- X
- int
- scan_logtail(int lastoff)
- X{
- char newpath[MAXPATHLEN], *s;
- int len;
- XFILE *logfp;
- path *curr;
- struct stat sb;
- X
- X if(lastoff < 0)
- X lastoff = 0;
- X if((logfp = fopen(logpath, "r")) == NULL)
- X return -1;
- X (void)fseek(logfp, lastoff, SEEK_SET);
- X while(fgets(newpath, MAXPATHLEN, logfp) != NULL)
- X {
- X for(s = newpath; *s; s++) if(*s == '\n') *s = '\0';
- X
- X if(lstat(newpath, &sb) < 0)
- X continue;
- X
- X for(curr = worklist; curr != NULL; curr = curr->next)
- X if(strcmp(curr->path, newpath) == 0) break;
- X
- X if(curr != NULL) /* Reset indicators on known file */
- X {
- X curr->ctime = sb.st_ctime;
- X#ifdef UNPACK_IN_PLACE
- X curr->pid = -1;
- X (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
- X#endif
- X continue;
- X }
- X
- X if(freelist != NULL)
- X {
- X curr = freelist;
- X freelist = freelist->next;
- X }
- X else
- X if((curr = (path *)malloc(sizeof(path))) == NULL)
- X continue;
- X
- X (void)strcpy(curr->path, newpath);
- X#ifdef UNPACK_IN_PLACE
- X curr->pid = -1;
- X (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
- X#endif
- X curr->atime = sb.st_atime;
- X curr->ctime = sb.st_ctime;
- X curr->next = worklist;
- X worklist = curr;
- X } /* while */
- X lastoff = ftell(logfp);
- X (void)fclose(logfp);
- X return lastoff;
- X} /* scan_logtail */
- X
- X
- X#ifdef UNPACK_IN_PLACE
- int
- is_dir_local(char *dir)
- X{
- X#if defined(ULTRIX)
- struct fs_data fsbuf;
- int success = 1; /* Returns 0 on "NOT MOUNTED" */
- X#else
- struct statfs fsbuf; /* Statfs buffer to check local versus NFS executable */
- int success = 0;
- X#endif
- X
- X#if defined(IRIX)
- X if(statfs(dir, &fsbuf, (int)(sizeof(struct statfs)), 0) < success)
- X#else
- X if(statfs(dir, &fsbuf) < success)
- X#endif
- X return -1;
- X
- X /* NFS Version 2 returns -1 or 0 for both free inodes, and total */
- X /* inodes to a client, so return false on this condition. */
- X
- X#if defined(ULTRIX)
- X if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
- X#else
- X if((fsbuf.f_files <= 0) && (fsbuf.f_ffree <= 0))
- X#endif
- X return 0;
- X return 1;
- X} /* is_dir_local */
- X#endif
- X
- X
- int
- is_tcx(int fd)
- X{
- int i;
- unsigned char c;
- X
- X for(i = 0; i < 256; i++)
- X if(read(fd, &c, 1) < 1 || c == 0)
- X break;
- X if((i >= 256) || read(fd, &c, 1) < 1 || c != 76 || read(fd, &c, 1) < 1 || c != 193
- X || read(fd, &c, 1) < 1 || c != 13 || read(fd, &c, 1) < 1 || c != 138 )
- X return 0;
- X return 1;
- X} /* is_tcx */
- X
- X
- int
- dodecode(int infd, int outfd)
- X{
- int pid;
- X#if defined(IRIX) || defined(AIX)
- int status;
- X#else
- union wait status;
- X#endif
- X
- X pid = fork();
- X if(pid < 0) return -1;
- X if(pid == 0)
- X {
- X if(dup2(infd, 0) < 0) exit(-1); /* Attach infd to stdin */
- X (void)close(infd);
- X if(dup2(outfd, 1) < 0) exit(-1); /* Attach outfd to stdout */
- X (void)close(outfd);
- X#ifdef UNPACKOPTS
- X (void)execl(PATHUNPACK, PATHUNPACK, UNPACKOPTS, (char *)0);
- X#else
- X (void)execl(PATHUNPACK, PATHUNPACK, (char *)0);
- X#endif
- X exit(-1);
- X }
- X else
- X pid = wait(&status);
- X return WEXITSTATUS(status);
- X} /* dodecode */
- X
- X
- X#ifdef ULTRIX
- int
- usleep(int usec)
- X{
- struct itimerval value, dumb;
- X
- X (void)signal(SIGALRM, usleep_sig);
- X
- X if(getitimer(ITIMER_REAL, &value) != 0)
- X {
- X perror("Error: couldn't get timer");
- X return(-1);
- X }
- X value.it_value.tv_sec = value.it_interval.tv_sec = (long) usec / 1000000;
- X value.it_value.tv_usec = value.it_interval.tv_usec = (long) usec % 1000000;
- X
- X if(setitimer(ITIMER_REAL, &value, &dumb) != 0) /* ignore parameter 3 */
- X {
- X perror("Error: couldn't set timer");
- X return(-1);
- X }
- X
- X (void)sigpause(SIGALRM);
- X
- X if(getitimer(ITIMER_REAL, &value) != 0)
- X {
- X perror("Error: couldn't get timer");
- X return(-1);
- X }
- X usec = (value.it_value.tv_sec - value.it_interval.tv_sec) * 1000000;
- X usec += (value.it_value.tv_usec - value.it_interval.tv_usec);
- X return usec;
- X}
- X
- int
- usleep_sig()
- X{
- X} /* usleep_sig */
- X#endif
- END_OF_FILE
- if test 31646 -ne `wc -c <'untcx.c'`; then
- echo shar: \"'untcx.c'\" unpacked with wrong size!
- fi
- # end of 'untcx.c'
- fi
- echo shar: End of archive 1 \(of 1\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have the archive.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-